/*
 * VisualClassComponentClase.cpp
 *
 *  Created on: May 29, 2013
 *      Author: root
 */

#include "gui/VisualComponents/clases/VisualClassComponentClase.h"
#include "model/clases/Clase.h"
#include "gui/Dibujar/AuxiliarDibujar.h"
#include "model/Utils.h"

VisualClassComponentClase::VisualClassComponentClase(Diagram *diagram) : VisualDiagramComponent(diagram), VisualClassesComponent(diagram) {
	m_component = new Clase();
	//for testing
	//((Clase*)m_component)->addAtributo(new Atributo("int",PRIVATE,"metodo",false,""));
	initialize();
	x0 = y0 = xf = yf = 0;
}

VisualClassComponentClase::VisualClassComponentClase(const VisualClassComponentClase & other) : VisualDiagramComponent(other.m_diagram), VisualClassesComponent(other.m_diagram)
{
	m_component = new Clase(*dynamic_cast<Clase*>(other.m_component));
	initialize();
}

VisualClassComponentClase::~VisualClassComponentClase() {
}

InfluenceArea VisualClassComponentClase::getInfluenceArea() {
	return InfluenceRectangle(x0, y0, xf, yf);
}

VisualClassesComponent* VisualClassComponentClase::getCopy(Diagram* diagram)
{
	Diagram* origen = m_diagram;
	m_diagram = diagram;
	VisualClassesComponent* comp = new VisualClassComponentClase(*this);
	m_diagram = origen;
	return comp;
}

void VisualClassComponentClase::draw(Cairo::RefPtr<Cairo::Context> ptrContext){
	//std::cout << "DRAW: VisualClassComponentClase:" << m_component->getName() << std::endl;
	std::string name = this->m_component->getName() + (dynamic_cast<Clase*>(this->m_component))->getClassTypeString();
	ptrContext->save();
	int x = getX();
	x0 = xf = x;
	int y = getY();
	y0 = yf = y;

	//calculate width of the box
	//int VisualClassComponentClase::get_maxWidthText(Cairo::RefPtr<Cairo::Context> ptrContext)

	int widthBox = ENTITY_HORIZONTAL_LINE * 2;
	int widthBoxAux = get_maxWidthText(ptrContext);

	if (widthBoxAux > widthBox)
		widthBox = widthBoxAux;

	xf += widthBox + 2*CONECTOR_RADIUS;

	//class name rectangle
	if (m_selected)
		ptrContext->set_source_rgb(0, 1, 0);
	else
		ptrContext->set_source_rgb(0, 0, 0);
	ptrContext->rectangle(x + CONECTOR_RADIUS, y, widthBox,
	ENTITY_VERTICAL_LINE);
	ptrContext->stroke_preserve();
	ptrContext->set_source_rgb(COLOR_COMPONENT);
	ptrContext->fill();
	ptrContext->save();
	draw_text(ptrContext, x + CONECTOR_RADIUS, y, widthBox,
	ENTITY_VERTICAL_LINE, name, COLOR_IN_TEXT);
	ptrContext->restore();

	yf += ENTITY_VERTICAL_LINE;

	//class attributes rectangle
	int maxHeightTextAttributes = get_maxHeightTextAttributes(ptrContext);
	int heightTextAttributes = ENTITY_VERTICAL_LINE;
	heightTextAttributes =
			(maxHeightTextAttributes > heightTextAttributes) ?
					maxHeightTextAttributes : heightTextAttributes;

	yf += heightTextAttributes;

	if (m_selected)
		ptrContext->set_source_rgb(0, 1, 0);
	else
		ptrContext->set_source_rgb(0, 0, 0);
	ptrContext->rectangle(x + CONECTOR_RADIUS, y + ENTITY_VERTICAL_LINE,
			widthBox, heightTextAttributes);
	ptrContext->stroke_preserve();
	ptrContext->set_source_rgb(COLOR_COMPONENT);
	ptrContext->fill();
	ptrContext->save();
	draw_text_attributes(ptrContext, x + CONECTOR_RADIUS,
			y + ENTITY_VERTICAL_LINE, widthBox, heightTextAttributes,
			COLOR_IN_TEXT);
	ptrContext->restore();

	//class methods rectangle

	int maxHeightTextMethods = get_maxHeightTextMethods(ptrContext);
	int heightTextMethods = ENTITY_VERTICAL_LINE;
	heightTextMethods =
			(maxHeightTextMethods > heightTextMethods) ?
					maxHeightTextMethods : heightTextMethods;

	yf += heightTextMethods;

	if (m_selected)
		ptrContext->set_source_rgb(0, 1, 0);
	else
		ptrContext->set_source_rgb(0, 0, 0);
	ptrContext->rectangle(x + CONECTOR_RADIUS, y + ENTITY_VERTICAL_LINE + heightTextAttributes,
			widthBox, heightTextMethods);
	ptrContext->stroke_preserve();
	ptrContext->set_source_rgb(COLOR_COMPONENT);
	ptrContext->fill();
	ptrContext->save();
	draw_text_methods(ptrContext, x + CONECTOR_RADIUS,
			y + ENTITY_VERTICAL_LINE + heightTextAttributes, widthBox,
			ENTITY_VERTICAL_LINE, COLOR_IN_TEXT);
	ptrContext->restore();

	ptrContext->restore();

	(dynamic_cast<Clase*>(this->m_component))->refreshConnectors(widthBox, yf - getY());

}

void VisualClassComponentClase::draw_text(Cairo::RefPtr<Cairo::Context> ptrContext, int x, int y, int rectangle_width, int rectangle_height, std::string& name, int r, int g, int b){
	int text_width;
	int text_height;
	Pango::FontDescription font(FONT_DESCRIPTION);
	Glib::RefPtr < Pango::Layout > layout = Pango::Layout::create(ptrContext);
	ptrContext->set_source_rgb(r, g, b);
	layout->set_font_description(font);
	layout->set_text(name);
	//get the text dimensions
	layout->get_pixel_size(text_width, text_height);
	// Position the text in the middle
	ptrContext->move_to(x + ((rectangle_width - text_width) / 2),
			y + ((rectangle_height - text_height) / 2));
	layout->show_in_cairo_context(ptrContext);
	ptrContext->fill();
}

void VisualClassComponentClase::draw_text_attributes(Cairo::RefPtr<Cairo::Context> ptrContext, int x, int y, int rectangle_width, int rectangle_height, int r, int g, int b){
	int text_width;
	int text_height;
	Pango::FontDescription font(FONT_DESCRIPTION);
	Glib::RefPtr < Pango::Layout > layout = Pango::Layout::create(ptrContext);
	ptrContext->set_source_rgb(r, g, b);
	layout->set_font_description(font);
	std::vector<Atributo*> attributes = (dynamic_cast<Clase*>(m_component))->getAtributos();
	std::string attributes_String = "";
	for (std::vector<Atributo*>::iterator it = attributes.begin();
			it != attributes.end(); ++it) {
		attributes_String += ((Atributo*) (*it))->description();
		attributes_String += "\n";
	}
	layout->set_text(attributes_String);
	//get the text dimensions
	layout->get_pixel_size(text_width, text_height);
	// Position the text in the middle
	ptrContext->move_to(x, y);
	layout->show_in_cairo_context(ptrContext);
	ptrContext->fill();
}

void VisualClassComponentClase::draw_text_methods(Cairo::RefPtr<Cairo::Context> ptrContext, int x, int y, int rectangle_width, int rectangle_height, int r, int g, int b){
	int text_width;
	int text_height;
	Pango::FontDescription font(FONT_DESCRIPTION);
	Glib::RefPtr < Pango::Layout > layout = Pango::Layout::create(ptrContext);
	ptrContext->set_source_rgb(r, g, b);
	layout->set_font_description(font);
	std::vector<Metodo*> methods = (dynamic_cast<Clase*>(m_component))->getMetodos();
	std::string methods_String = "";
	for (std::vector<Metodo*>::iterator it = methods.begin();
			it != methods.end(); ++it) {
		methods_String += ((Metodo*) (*it))->description();
		methods_String += "\n";
	}
	layout->set_text(methods_String);
	//get the text dimensions
	layout->get_pixel_size(text_width, text_height);
	// Position the text in the middle
	ptrContext->move_to(x, y);
	layout->show_in_cairo_context(ptrContext);
	ptrContext->fill();
}

int VisualClassComponentClase::get_maxWidthText(Cairo::RefPtr<Cairo::Context> ptrContext){
	int max_text_width = 0;
	int text_width;
	int text_height;
	int EXTRA_WIDTH = 5;
	Pango::FontDescription font(FONT_DESCRIPTION);
	Glib::RefPtr < Pango::Layout > layout = Pango::Layout::create(ptrContext);
	layout->set_font_description(font);
	layout->set_text(m_component->getName());
	//get the text dimensions
	layout->get_pixel_size(text_width, text_height);
	max_text_width = text_width;
	/*
	 * max width className
	 */
	std::string name = this->m_component->getName() + (dynamic_cast<Clase*>(this->m_component))->getClassTypeString();
	layout->set_text(name);
	layout->get_pixel_size(text_width, text_height);
	if (max_text_width < text_width)
		max_text_width = text_width;
	/*
	 * max width attributes
	 */
	std::vector<Atributo*> attributes = (dynamic_cast<Clase*>(m_component))->getAtributos();
	std::string attributes_String = "";
	for (std::vector<Atributo*>::iterator it = attributes.begin();
			it != attributes.end(); ++it) {
		attributes_String += ((Atributo*) (*it))->description();
		attributes_String += "\n";
	}
	layout->set_text(attributes_String);
	layout->get_pixel_size(text_width, text_height);
	if(max_text_width<text_width)
		max_text_width = text_width;
	/*
	 * max width methods
	 */
	std::vector<Metodo*> methods = (dynamic_cast<Clase*>(m_component))->getMetodos();
	std::string methods_String = "";
	for (std::vector<Metodo*>::iterator it = methods.begin();
			it != methods.end(); ++it) {
		methods_String += ((Metodo*) (*it))->description();
		methods_String += "\n";
	}
	layout->set_text(methods_String);
	layout->get_pixel_size(text_width, text_height);
	if(max_text_width<text_width)
		max_text_width = text_width;
	return max_text_width + EXTRA_WIDTH;
}

int VisualClassComponentClase::get_maxHeightTextAttributes(Cairo::RefPtr<Cairo::Context> ptrContext){
	int max_text_height = 0;
	int text_width;
	int text_height;
	Pango::FontDescription font(FONT_DESCRIPTION);
	Glib::RefPtr < Pango::Layout > layout = Pango::Layout::create(ptrContext);
	layout->set_font_description(font);
	/*
	 * max height attributes
	 */
	std::vector<Atributo*> attributes = (dynamic_cast<Clase*>(m_component))->getAtributos();
	std::string attributes_String = "";
	for (std::vector<Atributo*>::iterator it = attributes.begin();
			it != attributes.end(); ++it) {
		attributes_String += ((Atributo*) (*it))->description();
		attributes_String += "\n";
	}
	if (attributes_String.size() > 0)
		attributes_String.erase(attributes_String.size() - 1, 1);
	layout->set_text(attributes_String);
	layout->get_pixel_size(text_width, text_height);
	if(max_text_height<text_height)
		max_text_height = text_height;
	return max_text_height;
}

int VisualClassComponentClase::get_maxHeightTextMethods(Cairo::RefPtr<Cairo::Context> ptrContext){
	int max_text_height = 0;
	int text_width;
	int text_height;
	Pango::FontDescription font(FONT_DESCRIPTION);
	Glib::RefPtr < Pango::Layout > layout = Pango::Layout::create(ptrContext);
	layout->set_font_description(font);
	/*
	 * max height methods
	 */
	std::vector<Metodo*> methods = (dynamic_cast<Clase*>(m_component))->getMetodos();
	std::string methods_String = "";
	for (std::vector<Metodo*>::iterator it = methods.begin();
			it != methods.end(); ++it) {
		methods_String += ((Metodo*) (*it))->description();
		methods_String += "\n";
	}
	if (methods_String.size() > 0)
		methods_String.erase(methods_String.size() - 1, 1);
	layout->set_text(methods_String);
	layout->get_pixel_size(text_width, text_height);
	if(max_text_height<text_height)
		max_text_height = text_height;
	return max_text_height;
}

VisualComponentConector *VisualClassComponentClase::getConectorParaIdDeMapeoDeEntidad(int i) {
	Clase *clase = dynamic_cast<Clase *>(m_component);
	VisualComponentConector *visualConnectorBuscado = NULL;

	int indiceDelConector = clase->indiceDeConectorParaIdDeConectorDeEntidad(i);
	VisualComponentConector *visualConectorActual = getConectorEnIndice(indiceDelConector);

	if (i == 0) {
		visualConectorActual = getConectorLibre();
	}

	if (visualConectorActual->getVia() == NULL) {
		visualConnectorBuscado = visualConectorActual;
	}

	int offset = 1;
	while (visualConnectorBuscado == NULL) {
		int indiceActual = std::min<int>(indiceDelConector + offset, conectoresEntrantes.size() - 1);
		visualConectorActual = getConectorEnIndice(indiceActual);

		if (visualConectorActual->getVia() == NULL) {
			visualConnectorBuscado = visualConectorActual;
		} else {
			int indiceActual = std::max<int>(indiceDelConector - offset, 0);
			visualConectorActual = getConectorEnIndice(indiceActual);

			if (visualConectorActual->getVia() == NULL) {
				visualConnectorBuscado = visualConectorActual;
			}
		}
	}

	return visualConnectorBuscado;
}

VisualComponentConector *VisualClassComponentClase::getConectorParaIdDeMapeoDeRelacion(int i) {
	Clase *clase = dynamic_cast<Clase *>(m_component);
	VisualComponentConector *visualConnectorBuscado = NULL;

	int indiceDelConector = clase->indiceDeConectorParaIdDeConectorDeRelacion(i);
	VisualComponentConector *visualConectorActual = getConectorEnIndice(indiceDelConector);

	if (visualConectorActual->getVia() == NULL) {
		visualConnectorBuscado = visualConectorActual;
	}

	int offset = 1;
	while (visualConnectorBuscado == NULL) {
		int indiceActual = std::min<int>(indiceDelConector + offset, conectoresEntrantes.size() - 1);
		visualConectorActual = getConectorEnIndice(indiceActual);

		if (visualConectorActual->getVia() == NULL) {
			visualConnectorBuscado = visualConectorActual;
		} else {
			int indiceActual = std::max<int>(indiceDelConector - offset, 0);
			visualConectorActual = getConectorEnIndice(indiceActual);

			if (visualConectorActual->getVia() == NULL) {
				visualConnectorBuscado = visualConectorActual;
			}
		}
	}

	return visualConnectorBuscado;
}
